#pragma once
#include <iostream>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <pthread.h>
#include <memory>

#include "Log.hpp"
#include "InetAddr.hpp"

namespace socket_ns
{
    using namespace log_ns;

    using SockSPtr = std::shared_ptr<Socket>;
    // 用于实现:自动内存管理 和 共享资源所有权。
    // 它的核心作用是通过引用计数（Reference Counting）机制，确保多个指针可以安全地共享同一动态分配的对象，并在对象不再需要时自动释放内存。

    class Socket;

    enum
    {
        SOCKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERR
    };

    const static int gblcklog = 8; // gblcklog参数控制：Server请求队列长度，防止资源耗尽

    // 模板方法模式
    class Socket
    {
    public:
        virtual void CreateSocketOrDie() = 0;
        virtual void CreateBindOrDie(uint16_t port) = 0;
        virtual void CreateListenOrDie(int backlog = gblcklog) = 0;
        virtual SockSPtr Accepter(InetAddr *cliaddr) = 0;
        virtual bool Conntecor(const std::string &peerip, uint16_t peerport) = 0;
        virtual int Sockfd() = 0;
        virtual void Close() = 0;

        virtual ssize_t Recv(std::string *out) = 0;
        virtual ssize_t Send(const std::string &in) = 0;

    public:
        void BuildListenSocket(uint16_t port)
        {
            CreateSocketOrDie();
            CreateBindOrDie(port);
            CreateListenOrDie();
        }
        bool BuildClientSocket(const std::string &peerip, uint16_t peerport)
        {
            CreateSocketOrDie();
            return Conntecor(peerip, peerport);
        }
    };

    class TcpSocket : public Socket // 继承
    {
    public:
        TcpSocket()
        {
        }
        TcpSocket(int sockfd) : _sockfd(sockfd)
        {
        }
        ~TcpSocket()
        {
        }

        // 1、创建套接字socket
        void CreateSocketOrDie() override
        {
            _sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL, "socket create fail\n");
                exit(SOCKET_ERROR);
            }
            LOG(INFO, "socket create success, sockfd: %d\n", _sockfd); // 3,因为文件描述符012已经被占用了！
        }

        // 2、绑定：bind sockfd 和 Socket addr
        void CreateBindOrDie(uint16_t port) override
        {
            // 注意：在绑定之前务必先：统一处理一下sockaddr_in结构体!!!!!!!!
            struct sockaddr_in local;

            memset(&local, 0, sizeof(local));

            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;

            // bind sockfd 和 Socket addr
            if (::bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                LOG(FATAL, "bind error\n");
                exit(BIND_ERROR);
            }
            LOG(INFO, "bind success, sockfd: %d\n", _sockfd); // 3
        }

        // 3、监听（因为tcp是面向连接的，tcp需要未来不断地能够做到获取连接）
        // 监听操作的作用是让服务器进入被动打开状态，等待客户端的连接请求。
        // 这时候，服务器会维护一个等待连接请求的队列，当客户端发起连接时，服务器可以接受并建立连接。
        void CreateListenOrDie(int backlog) override
        {
            if (::listen(_sockfd, gblcklog) < 0)
            {
                LOG(FATAL, "listen error\n");
                exit(LISTEN_ERR);
            }
            LOG(INFO, "listen success\n");
        }

        // 4. accept 获取新连接
        // accept()的作用：从已完成连接队列中提取一个连接，创建新套接字用于通信。
        // 成功：返回一个新的套接字描述符（用于后续通信）。
        // 失败：返回-1（需检查错误码，如EAGAIN或EWOULDBLOCK）
        SockSPtr Accepter(InetAddr *cliaddr) override
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            // 提取
            int sockfd = ::accept(_sockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error\n");
                return nullptr;
            }

            *cliaddr = InetAddr(client);

            // 获得新链接成功
            LOG(INFO, "get a new link, client info : %s, sockfd is : %d\n", cliaddr->AddrStr().c_str(), sockfd);

            return std::make_shared<TcpSocket>(sockfd); // C++14
        }

        // 连接新链接，处理
        bool Conntecor(const std::string &peerip, uint16_t peerport) override
        {
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));

            server.sin_family = AF_INET;
            server.sin_port = htons(peerport);
            ::inet_pton(AF_INET, peerip.c_str(), &server.sin_addr);

            int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
            if (n < 0)
            {
                return false;
            }
            return true;
        }

        int Sockfd()
        {
            return _sockfd;
        }

        void Close()
        {
            if(_sockfd>0)
            {
                ::close(_sockfd);
            }
        }

        ssize_t Recv(std::string *out)override
        {
            char inbuffer[4096];
            ssize_t n=::recv(_sockfd,inbuffer,sizeof(inbuffer)-1,0);
            if(n>0)
            {
                inbuffer[n]=0;
                *out+=inbuffer;

            }
            return n;
        }

        ssize_t Send(const std::string &in)override
        {
            return send(_sockfd,in.c_str(),in.size(),0);
        }

    private:
        int _sockfd;
    };
}